﻿using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using AutoMapper;
using CollegeSim.CourseScheduler.Domain.DTO;
using CollegeSim.CourseScheduler.Domain.Services;
using CollegeSim.CourseScheduler.Persistence;
using Course = CollegeSim.CourseScheduler.Domain.Entities.Course;
using Instructor = CollegeSim.CourseScheduler.Domain.Entities.Instructor;

namespace CollegeSim.CourseScheduler.Facade
{
    // Author: Ryan Redburn
    // Project: Course Scheduler
    // Date: 2/12/2014

    #region [ Updates ]

    // Author: Ryan Redburn
    // Date: 3/2/2014
    // Revision:

    // TODO add temp data refreshes where appropriate

    #endregion

    public sealed class SchedulerFacade
    {
        #region [ Fields ]
        
        // Domain Services
        private readonly CourseService _courseService;
        private readonly InstructorService _instructorService;

        // Temp Data Stores
        private List<CourseDto> _courses;
        private List<InstructorDto> _instructors; 

        #endregion

        #region [ Constructors ]

        // Prepare Facade on instantiation
        public SchedulerFacade()
        {
            // Create Domain Services with required repositories

            // Course
            var courseRepo = new CourseRepository();
            var instructorRepo = new InstructorRepository();

            // Instructor
            _courseService = new CourseService(courseRepo);
            _instructorService = new InstructorService(instructorRepo);

            // Student
            // TODO create Student service


            // Create object maps

            // Domain
            Mapper.CreateMap<Course, CourseDto>();
            Mapper.CreateMap<CourseDto, Course>();
            Mapper.CreateMap<Instructor, InstructorDto>();
            Mapper.CreateMap<InstructorDto, Instructor>();
            // TODO add Student maps

            // Persistence
            Mapper.CreateMap<Persistence.Course, CourseDto>();
            Mapper.CreateMap<CourseDto, Persistence.Course>();
            Mapper.CreateMap<Persistence.Instructor, InstructorDto>();
            Mapper.CreateMap<InstructorDto, Persistence.Instructor>();
            // TODO add Student maps

            // Initialize temp data
            GetTempData();
        }

        #endregion

        #region [ Methods ]

        #region [ General ]

        /// <summary>
        /// Initailizes temporary data for facade use.
        /// </summary>
        private void GetTempData()
        {
            _courses = _courseService.GetAll();
            _instructors = _instructorService.GetAll();
            // TODO add Student data
        }

        #endregion

        #region [ Course ]

        /// <summary>
        /// Creates a new course.
        /// </summary>
        /// <param name="crn">Four character course reference number.</param>
        /// <param name="subject">Three character course subject.</param>
        /// <param name="courseNumber">Three character course number</param>
        /// <param name="title">Course title.</param>
        /// <param name="creditHours">Number of course credit hours. Must be in the range of 1-6.</param>
        /// <param name="contactHours">Number of contact hours. Must be in the range of 1-6.</param>
        /// <param name="isOnline">Course style.</param>
        /// <param name="instructor">Integer id of the teaching instructor.</param>
        public void CreateCourse(string crn, string subject, string courseNumber, string title, int creditHours, int contactHours, bool isOnline, string instructor)
        {
            // New Course
            var newCourse = new CourseDto
            {
                CRN = crn,
                Subject = subject,
                CourseNumber = courseNumber,
                Title = title,
                CreditHours = creditHours,
                ContactHours= contactHours,
                IsOnline = isOnline,
                InstructorId = _instructors.Single(i => i.Id + " - " + i.LastName + ", " + i.FirstName == instructor).Id
            };

            // Giving new Course to the CourseService for validation and persistence
            _courseService.CommitCourse(newCourse);
        }

        /// <summary>
        /// Uodates an existing course.
        /// </summary>
        /// <param name="id">Integer id</param>>
        /// <param name="crn">Four character course reference number.</param>
        /// <param name="subject">Three character course subject.</param>
        /// <param name="courseNumber">Three character course number</param>
        /// <param name="title">Course title.</param>
        /// <param name="creditHours">Number of course credit hours. Must be in the range of 1-6.</param>
        /// <param name="contactHours">Number of contact hours. Must be in the range of 1-6.</param>
        /// <param name="isOnline">Course style.</param>
        /// <param name="instructor">Integer id of the teaching instructor.</param>
        public void UpdateCourse(int id, string crn, string subject, string courseNumber, string title, int creditHours, int contactHours, bool isOnline, string instructor)
        {
            // Course to update
            var courseUpdate = new CourseDto
            {
                Id = id,
                CRN = crn,
                Subject = subject,
                CourseNumber = courseNumber,
                Title = title,
                CreditHours = creditHours,
                ContactHours = contactHours,
                IsOnline = isOnline,
                InstructorId = _instructors.Single(i => i.Id + " - " + i.LastName + ", " + i.FirstName == instructor).Id
            };

            // Giving updated Course to the CourseService for validation and persistence
            _courseService.CommitCourse(courseUpdate);
        }

        /// <summary>
        /// Gets a course using the given CRN.
        /// </summary>
        /// <param name="crn">Four character course reference number.</param>
        /// <returns>List of string course information. CRN, subject, course number, title, creditshours, contacthours, is online, instructor last name.</returns>
        public List<string> GetCourseByCRN(string crn)
        {
            var course = _courseService.GetByCRN(crn);

            // Create string list with course info
            var courseInfo = new List<string>
            {
                course.CRN,
                course.Subject,
                course.CourseNumber,
                course.Title,
                course.CreditHours.ToString(CultureInfo.InvariantCulture),
                course.ContactHours.ToString(CultureInfo.InvariantCulture),
                course.IsOnline ? "Yes" : "No",
                _instructorService.GetById(course.InstructorId).LastName
            };

            return courseInfo;
        }

        /// <summary>
        /// Returns a list of string course representations.
        /// </summary>
        /// <returns>String list, CRN + Subject + CourseNumber + Title</returns>
        public List<string> GetCourseList()
        {
            var courses = _courseService.GetAll();
            return courses.Select(c => c.CRN + "" + c.Subject + c.CourseNumber + " " + c.Title).ToList();

        }

        /// <summary>
        /// Returns a table containing all courses.
        /// </summary>
        /// <returns>DataTable of Course info.</returns>
        public DataTable GetCourseTable()
        {
            // Retrieve table resources
            var courses = _courseService.GetAll();
            var instructors = _instructorService.GetAll();

            // Create course table
            var courseTable = new DataTable();
            courseTable.Columns.Add("CRN", typeof (string));
            courseTable.Columns.Add("Subject", typeof (string));
            courseTable.Columns.Add("Course Number", typeof (string));
            courseTable.Columns.Add("Title", typeof (string));
            courseTable.Columns.Add("Credit Hours", typeof (int));
            courseTable.Columns.Add("Contact Hours", typeof (int));
            courseTable.Columns.Add("Online", typeof (bool));
            courseTable.Columns.Add("Instructor", typeof (string));

            // Add course rows
            foreach (var c in courses)
            {
                courseTable.Rows.Add(c.CreditHours, c.Subject, c.CourseNumber, c.Title, c.CreditHours, c.ContactHours,
                    c.IsOnline, instructors.Single(i => i.Id == c.InstructorId).LastName);
            }

            return courseTable;
        }

        #endregion

        #region [ Instructor ]

        /// <summary>
        /// Creates a new instructor.
        /// </summary>
        /// <param name="firstName">Instructor first name.</param>
        /// <param name="lastName">instructor last name</param>
        /// <param name="phoneNumber">Instructor phone number</param>
        /// <param name="email">Instructor email.</param>
        /// <param name="officeNumber">Instructor office number.</param>
        public void CreateInstructor(string firstName, string lastName, string phoneNumber = null, string email = null, string officeNumber = null)
        {
            // New Instructor
            var newInstructor = new InstructorDto
            {
                FirstName = firstName,
                LastName = lastName,
                PhoneNumber = phoneNumber,
                Email = email,
                OfficeNumber = officeNumber
            };

            // Giving new Instructor to the InstructorService for validation and persistence
            _instructorService.CommitInstructor(newInstructor);
        }

        /// <summary>
        /// Returns a list of string instructor representations.
        /// </summary>
        /// <returns>String list, "id - lastname, firstname".</returns>
        public List<string> GetInstructorList()
        {
            var instructors = _instructorService.GetAll();
            return instructors.Select(i => i.Id + " - " + i.LastName + ", " + i.FirstName).ToList();
        }

        #endregion

        #endregion
    }
}
